using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace XMTAEditor.Controls
{
	public partial class CheckBoxList : ScrollableControl
	{
		internal const int lrPadding = 3, tPadding = 2;
		internal static readonly ContentAlignment anyRightAlignment, anyCenterAlignment, anyBottomAlignment, anyMiddleAlignment;
		internal static ToolTip toolTip;
		private Timer hoverTimer;
		private int timedHoverItem = -1;

		private int idealHeight = 100;

		static CheckBoxList()
		{
			anyRightAlignment = ContentAlignment.TopRight | ContentAlignment.MiddleRight | ContentAlignment.BottomRight;
			anyCenterAlignment = ContentAlignment.TopCenter | ContentAlignment.MiddleCenter | ContentAlignment.BottomCenter;
			anyBottomAlignment = ContentAlignment.BottomLeft | ContentAlignment.BottomCenter | ContentAlignment.BottomRight;
			anyMiddleAlignment = ContentAlignment.MiddleLeft | ContentAlignment.MiddleCenter | ContentAlignment.MiddleRight;
			toolTip = new ToolTip();
		}

		public CheckBoxList()
		{
			base.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.CacheText | ControlStyles.SupportsTransparentBackColor | ControlStyles.StandardClick | ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
			items = new CheckBoxListItemCollection(this);
			InitializeComponent();
			hoverTimer = new Timer();
			hoverTimer.Interval = SystemInformation.MouseHoverTime;
			hoverTimer.Tick += new EventHandler(hoverTimer_Tick);
			this.AutoSize = true;
		}

		void hoverTimer_Tick(object sender, EventArgs e)
		{
			hoverTimer.Stop();
			if (mouseTracking && timedHoverItem == hoverItem)
			{
				UpdateToolTip(items[timedHoverItem].ToolTipText);
			}
		}

		protected override void OnAutoSizeChanged(EventArgs e)
		{
			base.OnAutoSizeChanged(e);
		}

		protected override void OnEnabledChanged(EventArgs e)
		{
			base.OnEnabledChanged(e);
		}

		protected override void OnGotFocus(EventArgs e)
		{
			base.OnGotFocus(e);
			if (focusedIndex != -1)
				Invalidate(this.FocusedItem.Bounds);
		}

		protected override void OnLostFocus(EventArgs e)
		{
			base.OnLostFocus(e);
			if (focusedIndex != -1)
				Invalidate(this.FocusedItem.Bounds);
		}

		private int pressingItem = -1;

		private void InvalidateItemGlyph(int index)
		{
			if (index != -1)
			{
				using (Graphics g = base.CreateGraphics())
					base.Invalidate(new Rectangle(items[index].GlyphPosition, GetItemGlyphSize(g, items[index])));
			}
		}

		protected override void OnKeyDown(KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Space)
			{
				pressingItem = this.focusedIndex;
				InvalidateItemGlyph(pressingItem);
				base.Update();
				e.Handled = true;
			}
			base.OnKeyDown(e);
		}

		protected override void OnKeyUp(KeyEventArgs e)
		{
			if (pressingItem != -1)
			{
				int ci = pressingItem;
				pressingItem = -1;
				InvalidateItemGlyph(ci);
			}
			// Handle button press on Space
			base.OnKeyUp(e);
		}

		protected override bool ProcessDialogKey(Keys keyData)
		{
			switch ((keyData & Keys.KeyCode))
			{
				case Keys.Space:
				case Keys.Prior:
				case Keys.Next:
				case Keys.End:
				case Keys.Home:
				case Keys.Left:
				case Keys.Up:
				case Keys.Right:
				case Keys.Down:
				case Keys.Return:
					KeyEventArgs args1 = new KeyEventArgs(keyData);
					if (this.ProcessKey(args1))
						return true;
					break;
				default:
					break;
			}
			return base.ProcessDialogKey(keyData);
		}

		protected override bool ProcessKeyPreview(ref Message m)
		{
			if (m.Msg == 0x100)
			{
				KeyEventArgs args1 = new KeyEventArgs(((Keys)((int)((long)m.WParam))) | Control.ModifierKeys);
				switch (args1.KeyCode)
				{
					case Keys.Space:
					case Keys.Prior:
					case Keys.Next:
					case Keys.End:
					case Keys.Home:
					case Keys.Left:
					case Keys.Up:
					case Keys.Right:
					case Keys.Down:
					case Keys.Return:
						return this.ProcessKey(args1);
					default:
						break;
				}
			}
			else if (m.Msg == 0x101)
			{
				KeyEventArgs args2 = new KeyEventArgs(((Keys)((int)((long)m.WParam))) | Control.ModifierKeys);
				if (args2.KeyCode == Keys.Tab)
				{
					return this.ProcessKey(args2);
				}
			}

			return base.ProcessKeyPreview(ref m);
		}

		protected bool ProcessKey(KeyEventArgs ke)
		{
			System.Diagnostics.Debug.WriteLine("Key pressed: " + ke.KeyCode.ToString());
			bool ret = false;
			switch (ke.KeyCode)
			{
				case Keys.Down:
				case Keys.Right:
					if (FocusNextItem(this.FocusedItem, true))
						ret = true;
					break;
				case Keys.Enter:
					break;
				case Keys.Escape:
					break;
				case Keys.Up:
				case Keys.Left:
					if (FocusNextItem(this.FocusedItem, false))
						ret = true;
					break;
				case Keys.Space:
					ToggleItem(focusedIndex);
					break;
				case Keys.Tab:
					if (FocusNextItem(this.FocusedItem, !ke.Shift))
						ret = true;
					break;
				default:
					break;
			}
			if (ret) ke.SuppressKeyPress = true;
			return ret;
		}

		protected override void OnLayout(LayoutEventArgs e)
		{
			base.OnLayout(e);
			ResetListLayout();
		}

		protected override void OnMouseDown(MouseEventArgs e)
		{
			base.OnMouseDown(e);
			pressingItem = GetItemAtLocation(e.Location);
			if (pressingItem >= 0)
			{
				this.Focus();
				SetFocused(pressingItem);
				InvalidateItemGlyph(pressingItem);
				Invalidate(FocusedItem.Bounds);
			}
			base.Update();
		}

		protected override void OnMouseUp(MouseEventArgs e)
		{
			int ci = pressingItem;
			pressingItem = -1;
			InvalidateItemGlyph(ci);
			base.OnMouseUp(e);
		}

		protected override void OnMouseClick(MouseEventArgs e)
		{
			base.OnMouseClick(e);
			if (hoverItem != -1)
				ToggleItem(hoverItem);
		}

		private int GetItemAtLocation(Point pt)
		{
			for (int i = 0; i < items.Count; i++)
			{
				if (items[i].Bounds.Contains(pt))
					return i;
			}
			return -1;
		}

		private int hoverItem = -1;

		private void SetFocused(int itemIndex)
		{
			int oldSelect = focusedIndex;
			focusedIndex = itemIndex;
			// clear old selected item
			if (oldSelect > -1)
			{
				InvalidateItemGlyph(oldSelect);
				if (this.Focused)
					Invalidate(items[oldSelect].TextRect);
			}
			// Set new item
			if (itemIndex > -1)
			{
				InvalidateItemGlyph(focusedIndex);
				if (this.Focused)
					Invalidate(items[focusedIndex].TextRect);
			}
		}

		private void ToggleItem(int itemIndex)
		{
			if (itemIndex >= 0 && itemIndex < items.Count)
			{
				switch (items[itemIndex].State)
				{
					case CheckState.Checked:
						items[itemIndex].State = CheckState.Indeterminate;
						break;
					case CheckState.Unchecked:
						items[itemIndex].State = CheckState.Checked;
						break;
					default:
						items[itemIndex].State = CheckState.Unchecked;
						break;
				}
				InvalidateItemGlyph(itemIndex);
			}
		}

		private void SetHover(int itemIndex)
		{
			if (itemIndex != hoverItem)
			{
				hoverTimer.Stop();
				UpdateToolTip(null);
				int oldHover = hoverItem;
				hoverItem = itemIndex;
				// clear hover item
				if (oldHover != -1)
					InvalidateItemGlyph(oldHover);
				// Set hover item
				if (itemIndex != -1)
				{
					InvalidateItemGlyph(hoverItem);
					if (!string.IsNullOrEmpty(items[hoverItem].ToolTipText))
					{
						timedHoverItem = hoverItem;
						hoverTimer.Start();
					}
				}
			}
		}

		private bool mouseTracking = false;

		protected override void OnMouseEnter(EventArgs e)
		{
			base.OnMouseEnter(e);
			mouseTracking = true;
		}

		private void UpdateToolTip(string tiptext)
		{
			if (showToolTips)
			{
				toolTip.Hide(this);
				toolTip.Active = false;
				Cursor currentInternal = Cursor.Current;
				if (currentInternal != null)
				{
					System.Diagnostics.Debug.WriteLine(string.Format("Showing tooltip for item {0} = {1}", hoverItem, tiptext));
					toolTip.Active = true;
					Point position = Cursor.Position;
					position.Y += this.Cursor.Size.Height - currentInternal.HotSpot.Y;
					toolTip.Show(tiptext, this, base.PointToClient(position), toolTip.AutoPopDelay);
				}
			}
		}

		protected override void OnMouseLeave(EventArgs e)
		{
			base.OnMouseLeave(e);
			mouseTracking = false;
			SetHover(-1);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			base.OnMouseMove(e);
			if (mouseTracking)
				SetHover(GetItemAtLocation(e.Location));
		}

		protected override void OnStyleChanged(EventArgs e)
		{
			ResetListLayout();
			base.OnStyleChanged(e);
		}

		protected override bool ProcessMnemonic(char charCode)
		{
			if (this.Enabled && this.Visible && (this.Focused || base.ContainsFocus))
			{
				foreach (CheckBoxListItem item in items)
				{
					if (Control.IsMnemonic(charCode, item.Text))
					{
						int idx = items.IndexOf(item);
						SetFocused(idx);
						ToggleItem(idx);
						return true;
					}
				}
			}
			return false;
		}

		private int focusedIndex = -1;

		/*[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		Bindable(true), DefaultValue(-1), Category("Data"),
		Description("Gets or sets the index specifying the currently selected item.")]
		public int SelectedIndex
		{
			get { return selectedIndex; }
			set
			{
				if (selectedIndex != value)
				{
					if (value < -1 || value >= items.Count)
						throw new IndexOutOfRangeException();
					if (selectedIndex > -1)
						items[selectedIndex].State = 0;
					selectedIndex = value;
					items[selectedIndex].State = 1;
					OnSelectedIndexChanged(EventArgs.Empty);
				}
			}
		}

		public event EventHandler SelectedIndexChanged;

		protected virtual void OnSelectedIndexChanged(EventArgs e)
		{
			EventHandler handler1 = this.SelectedIndexChanged;
			if (handler1 != null)
				handler1(this, e);
		}*/

		private bool FocusNextItem(CheckBoxListItem i, bool forward)
		{
			if (items.Count > 0)
			{
				if (i == null)
				{
					if (forward)
						SetFocused(0);
					else
						SetFocused(items.Count - 1);
					return true;
				}
				else
				{
					int idx = items.IndexOf(i);
					if (idx == -1)
						throw new IndexOutOfRangeException();
					if ((idx == 0 && !forward) || (idx == (items.Count - 1) && forward))
						return false;
					if (forward)
						SetFocused(focusedIndex + 1);
					else
						SetFocused(focusedIndex - 1);
					return true;
				}
			}
			return false;
		}

		private CheckBoxListItem FocusedItem
		{
			get
			{
				if (this.focusedIndex == -1)
					return null;
				return items[this.focusedIndex];
			}
			set
			{
				focusedIndex = items.IndexOf(value);
			}
		}

		public override Size GetPreferredSize(Size proposedSize)
		{
			return new Size(this.Width, idealHeight);
		}

		protected internal virtual void ResetListLayout()
		{
			using (Graphics g = this.CreateGraphics())
			{
				// First get the base height of all items and the max height
				int maxItemHeight = 0;
				idealHeight = 0;
				for (int i = 0; i < items.Count; i++)
				{
					// Get glyph size
					Size glyphSize = this.GetItemGlyphSize(g, items[i]);

					// Calculate text size
					Size textSize = new Size(this.ClientRectangle.Width, Int32.MaxValue);
					if ((this.checkAlign & anyCenterAlignment) == (ContentAlignment)0)
						textSize.Width -= (glyphSize.Width + (lrPadding * 2));
					items[i].TextRect = new Rectangle(new Point(0, 0), this.GetItemTextSize(g, items[i], textSize));

					// Calculate minimum item height
					int minHeight = items[i].TextRect.Height;
					if ((this.checkAlign & ContentAlignment.TopCenter) != (ContentAlignment)0)
						minHeight += (glyphSize.Height + tPadding);
					else if ((this.checkAlign & ContentAlignment.BottomCenter) != (ContentAlignment)0)
						minHeight += glyphSize.Height;
					items[i].Bounds.Height = minHeight;
					maxItemHeight = Math.Max(maxItemHeight, minHeight);
					idealHeight += minHeight;
				}
				if (spaceEvenly) idealHeight = maxItemHeight * items.Count;
				// Add in padding between items
				idealHeight += ((items.Count - 1) * this.Margin.Vertical);
				idealHeight += tPadding;

				// Position the text and glyph of each item
				Point loc = new Point(0);
				for (int i = 0; i < items.Count; i++)
				{
					// Set bounds of the item
					items[i].Bounds = new Rectangle(loc, new Size(this.ClientRectangle.Width, spaceEvenly ? maxItemHeight : items[i].Bounds.Height));

					// Position glyph and text
					items[i].TextRect.Offset(loc);
					items[i].GlyphPosition = loc;
					Size glyphSize = this.GetItemGlyphSize(g, items[i]);
					if ((this.checkAlign & anyBottomAlignment) != (ContentAlignment)0)
					{
						items[i].GlyphPosition.Y = items[i].Bounds.Bottom - glyphSize.Height;
					}
					else if ((this.checkAlign & anyMiddleAlignment) != (ContentAlignment)0)
					{
						items[i].GlyphPosition.Y = (items[i].Bounds.Height - glyphSize.Height) / 2 + items[i].Bounds.Top;
					}
					else
					{
						items[i].GlyphPosition.Y = items[i].Bounds.Top + tPadding;
						if (this.checkAlign == ContentAlignment.TopCenter)
							items[i].TextRect.Offset(0, glyphSize.Height + tPadding);
					}
					if ((this.checkAlign & anyRightAlignment) != (ContentAlignment)0)
					{
						items[i].GlyphPosition.X = items[i].Bounds.Right - glyphSize.Width;
						items[i].TextRect.Offset(lrPadding, 0);
					}
					else if ((this.checkAlign & anyCenterAlignment) != (ContentAlignment)0)
					{
						items[i].GlyphPosition.X = (items[i].Bounds.Width - glyphSize.Width) / 2 + items[i].Bounds.Left;
					}
					else
					{
						items[i].TextRect.Offset(glyphSize.Width + lrPadding, 0);
					}

					// Adjust text position for bottom or middle
					if ((this.TextAlign & anyBottomAlignment) != (ContentAlignment)0)
					{
						items[i].TextRect.Offset(0, items[i].Bounds.Height - items[i].TextRect.Height);
					}
					else if ((this.TextAlign & anyMiddleAlignment) != (ContentAlignment)0)
					{
						items[i].TextRect.Offset(0, (items[i].Bounds.Height - items[i].TextRect.Height) / 2);
					}

					// Set top position of next item
					loc.Y += items[i].Bounds.Height + this.Margin.Vertical;
				}
			}

			// Set scroll height and autosize to ideal height
			this.AutoScrollMinSize = new Size(this.ClientRectangle.Width, idealHeight);
			if (this.AutoSize) this.Height = idealHeight;
		}

		protected Size GetItemGlyphSize(Graphics g, CheckBoxListItem item)
		{
			return CheckBoxRenderer.GetGlyphSize(g, System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal);
		}

		protected Size GetItemTextSize(Graphics g, CheckBoxListItem item, Size proposedSize)
		{
			Size tsz = TextRenderer.MeasureText(g, item.Text, this.Font, proposedSize, tff);
			Size stsz = new Size(0, 0);
			if (!string.IsNullOrEmpty(item.Subtext))
			{
				tsz.Height += subtextSeparatorHeight;
				stsz = TextRenderer.MeasureText(g, item.Subtext, this.SubtextFont, proposedSize, tff);
			}
			item.tHeight = tsz.Height;
			return new Size(proposedSize.Width, tsz.Height + stsz.Height);
		}

		private bool showToolTips = true;

		[DefaultValue(true), Category("Appearance")]
		public bool ShowItemToolTip
		{
			get { return showToolTips; }
			set { showToolTips = value; }
		}	

		private bool spaceEvenly = false;

		[DefaultValue(false), Category("Appearance")]
		public bool SpaceEvenly
		{
			get { return spaceEvenly; }
			set { spaceEvenly = value; ResetListLayout(); Refresh(); }
		}

		private CheckBoxListItemCollection items;

		[MergableProperty(false),
		Category("Data"),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		Localizable(true),
		Description("List of radio buttons with optional subtext")]
		public virtual CheckBoxListItemCollection Items
		{
			get { return items; }
			set { items = value; }
		}

		private Font subtextFont;

		[DefaultValue(null), Category("Appearance")]
		public Font SubtextFont
		{
			get { return subtextFont == null ? this.Font : subtextFont; }
			set { subtextFont = value; ResetListLayout(); Refresh(); }
		}

		internal void ResetSubtextFont()
		{
			SubtextFont = null;
		}

		internal bool ShouldSerializeSubtextFont()
		{
			return (subtextFont != null && subtextFont != this.Font);
		}

		private Color subtextForeColor = Color.Empty;

		[Category("Appearance")]
		public Color SubtextForeColor
		{
			get { return subtextForeColor == Color.Empty ? this.ForeColor : subtextForeColor; }
			set { subtextForeColor = value; OnSubtextForeColorChanged(new PropertyChangedEventArgs("SubtextForeColor")); Refresh(); }
		}

		internal bool ShouldSerializeSubtextForeColor()
		{
			return (subtextForeColor != Color.Empty && subtextForeColor != this.ForeColor);
		}

		public event PropertyChangedEventHandler SubtextForeColorChanged;

		protected virtual void OnSubtextForeColorChanged(PropertyChangedEventArgs e)
		{
			PropertyChangedEventHandler handler1 = this.SubtextForeColorChanged;
			if (handler1 != null)
				handler1(this, e);
		}

		private int subtextSeparatorHeight = 5;

		[DefaultValue(5), Category("Appearance")]
		public int SubtextSeparatorHeight
		{
			get { return subtextSeparatorHeight; }
			set { subtextSeparatorHeight = value; OnSubtextSeparatorHeightChanged(new PropertyChangedEventArgs("SubtextSeparatorHeight")); ResetListLayout(); Refresh(); }
		}

		public event PropertyChangedEventHandler SubtextSeparatorHeightChanged;

		protected virtual void OnSubtextSeparatorHeightChanged(PropertyChangedEventArgs e)
		{
			PropertyChangedEventHandler handler1 = this.SubtextSeparatorHeightChanged;
			if (handler1 != null)
				handler1(this, e);
		}

		private ContentAlignment checkAlign = ContentAlignment.TopLeft;

		[DefaultValue(true), Category("Appearance"), Description("Autosizes the control to fit the contents"), Browsable(true)]
		public override bool AutoSize
		{
			get
			{
				return base.AutoSize;
			}
			set
			{
				base.AutoSize = value;
			}
		}

		[DefaultValue(typeof(ContentAlignment), "TopLeft"), Description("CheckBoxCheckAlignDescr"), Category("Appearance"), Localizable(true)]
		public ContentAlignment CheckAlign
		{
			get { return checkAlign; }
			set { checkAlign = value; ResetListLayout(); Refresh(); }
		}

		private ContentAlignment textAlign = ContentAlignment.TopLeft;
		private TextFormatFlags tff = TextFormatFlags.WordBreak;

		[DefaultValue(typeof(ContentAlignment), "TopLeft"), Description("CheckBoxCheckAlignDescr"), Category("Appearance"), Localizable(true)]
		public ContentAlignment TextAlign
		{
			get { return textAlign; }
			set
			{
				textAlign = value;
				tff = TextFormatFlags.WordBreak;
				if ((this.textAlign & anyRightAlignment) != (ContentAlignment)0)
					tff |= TextFormatFlags.Right;
				else if ((this.textAlign & anyCenterAlignment) != (ContentAlignment)0)
					tff |= TextFormatFlags.HorizontalCenter;
				ResetListLayout();
				Refresh();
			}
		}

		protected virtual void PaintItemGlyph(Graphics g, CheckBoxListItem li)
		{
			System.Windows.Forms.VisualStyles.CheckBoxState rbs = (System.Windows.Forms.VisualStyles.CheckBoxState)(((int)li.State * 4) + 1);
			int idx = items.IndexOf(li);
			if (!this.Enabled)
				rbs += 3;
			else if (idx == pressingItem)
				rbs += 2;
			else if (idx == hoverItem)
				rbs++;
			//CheckBoxRenderer.DrawParentBackground(g, new Rectangle(li.GlyphPosition, CheckBoxRenderer.GetGlyphSize(g, rbs)), this);
			CheckBoxRenderer.DrawCheckBox(g, li.GlyphPosition, rbs);
		}

		protected virtual void PaintItemText(Graphics g, CheckBoxListItem li)
		{
			//CheckBoxRenderer.DrawParentBackground(g, li.TextRect, this);
			TextRenderer.DrawText(g, li.Text, this.Font, li.TextRect, this.ForeColor, tff);
			if (!string.IsNullOrEmpty(li.Subtext))
			{
				Rectangle tr = li.TextRect;
				tr.Offset(0, li.tHeight);
				tr.Height -= li.tHeight;
				TextRenderer.DrawText(g, li.Subtext, this.SubtextFont, tr, this.SubtextForeColor, tff);
			}
			if (items.IndexOf(li) == focusedIndex && this.Focused)
				ControlPaint.DrawFocusRectangle(g, li.TextRect);
		}

		protected override void OnPaint(PaintEventArgs pe)
		{
			CheckBoxRenderer.DrawParentBackground(pe.Graphics, pe.ClipRectangle, this);
			foreach (CheckBoxListItem li in this.items)
			{
				PaintItemGlyph(pe.Graphics, li);
				PaintItemText(pe.Graphics, li);
			}
		}
	}

	[Editor(typeof(System.ComponentModel.Design.CollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
	public class CheckBoxListItemCollection : EventedList<CheckBoxListItem>
	{
		private CheckBoxList parent;

		public void Add(string text, string subtext)
		{
			base.Add(new CheckBoxListItem(text, subtext));
		}

		public void Add(string text, string subtext, string tooltip)
		{
			base.Add(new CheckBoxListItem(text, subtext, tooltip));
		}

		internal CheckBoxListItemCollection(CheckBoxList list)
		{
			parent = list;
		}

		protected override void OnItemInserted(ItemAtEventArgs<CheckBoxListItem> e)
		{
			base.OnItemInserted(e);
			parent.ResetListLayout();
			parent.Refresh();
		}

		protected override void OnItemRemoved(ItemAtEventArgs<CheckBoxListItem> e)
		{
			base.OnItemRemoved(e);
			parent.ResetListLayout();
			parent.Refresh();
		}

		protected override void OnItemRangeInserted(ItemRangeEventArgs<CheckBoxListItem> e)
		{
			base.OnItemRangeInserted(e);
			parent.ResetListLayout();
			parent.Refresh();
		}

		protected override void OnItemRangeRemoved(ItemRangeEventArgs<CheckBoxListItem> e)
		{
			base.OnItemRangeRemoved(e);
			parent.ResetListLayout();
			parent.Refresh();
		}
		/*
		public bool[] States
		{
			get
			{
				return this.ConvertAll<bool>(delegate(CheckBoxListItem i) { return i.State != 0; }).ToArray();
			}
		}*/
	}

	[DefaultProperty("Text")]
	public class CheckBoxListItem
	{
		internal Point GlyphPosition;
		internal Rectangle TextRect, Bounds;
		internal int tHeight;

		private string text = string.Empty;
		private string subtext;
		private CheckState state;
		private string tooltip;

		public CheckBoxListItem()
		{
		}

		public CheckBoxListItem(string text, string subtext)
		{
			this.text = text; this.subtext = subtext;
		}

		public CheckBoxListItem(string text, string subtext, string tooltiptext) : this(text, subtext)
		{
			this.tooltip = tooltiptext;
		}

		[DefaultValue("")]
		public string Text
		{
			get { return text; }
			set { text = value; }
		}

		[DefaultValue((string)null)]
		public string Subtext
		{
			get { return subtext; }
			set { subtext = value; }
		}

		[DefaultValue(typeof(CheckState), "Indeterminate"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public System.Windows.Forms.CheckState State
		{
			get { return state; }
			set { state = value; }
		}

		[DefaultValue((string)null)]
		public string ToolTipText
		{
			get { return tooltip; }
			set { tooltip = value; }
		}

		internal bool Contains(Point pt)
		{
			return Bounds.Contains(pt);
		}
	}
}